package web

import (
	"reflect"

	"gddgame.cc/galaxy/server/web/middleware"
	"gddgame.cc/galaxy/utils/def"
)

var (
	SystemExceptionDetail           = def.GenerateExceptionDetail(500, "SYSTEM_ERROR", false)
	NotFoundExceptionResult         = def.GenerateException(404, "NOT_FOUND", true)(nil)
	MethodNotAllowedExceptionResult = def.GenerateException(405, "METHOD_NOT_ALLOWED", true)(nil)
)

func Restful(router Router) {
	router.Use(
		middleware.JSONMessageWrap(FormatHandler),
		middleware.ErrorHandlerWrap(ErrorHandler),
	)
	router.NotFound(NotFoundHandler)
	router.MethodNotAllowed(MethodNotAllowedHandler)
}

func TrackRestful(router Router, trackKey string) {
	router.Use(
		middleware.JSONMessageWrap(FormatHandler),
		middleware.ErrorHandlerWrap(ErrorHandler),
		middleware.TrackWrap(trackKey, middleware.HeaderLocation, trackKey),
	)
	router.NotFound(NotFoundHandler)
	router.MethodNotAllowed(MethodNotAllowedHandler)
}

type Response struct {
	Status  int         `json:"status"`
	Result  interface{} `json:"result"`
	Message interface{} `json:"message"`
}

type PageResult struct {
	List  interface{} `json:"list"`
	Page  int         `json:"page"`
	Total int         `json:"total"`
}

func ResponsePage(list interface{}, page int, total int) *PageResult {
	p := &PageResult{
		List:  list,
		Page:  page,
		Total: total,
	}
	if p.List == nil || reflect.ValueOf(p.List).IsNil() {
		p.List = []struct{}{}
	}
	return p
}

func success(result interface{}) Response {
	return Response{200, result, ""}
}

func throwError(status int, message interface{}, result interface{}) Response {
	return Response{status, result, message}
}

func ErrorHandler(context middleware.Context, err error, detail interface{}) {
	exception, ok := err.(def.Exception)
	if !ok {
		exception = SystemExceptionDetail(err, detail)
		context.SetResponse(exception)
	}
	context.Error(exception)
}

func NotFoundHandler(context middleware.Context, next middleware.Next) error {
	context.SetResponse(NotFoundExceptionResult)
	return next(nil)
}

// 会继续执行到其他method，所以设定response
func MethodNotAllowedHandler(context middleware.Context, next middleware.Next) error {
	context.SetResponse(MethodNotAllowedExceptionResult)
	return next(nil)
}

func FormatHandler(context middleware.Context) interface{} {
	response := context.GetResponse()
	exception, ok := response.(def.Exception)
	var r Response
	if ok {
		r = throwError(exception.No(), exception.Message(), exception.Detail())
	} else {
		r = success(response)
	}
	context.Debugf("[ Web ] Response: %s %#v", context.Request().RequestURI, r)
	return r
}
